﻿#include <iostream>
#include <vector>
//条款8：别让异常逃离析构函数

//C++并不禁止析构函数吐出异常
class Widget
{
public:
    ~Widget()
    {
        //假设这可能会引发异常
    } //允许派生类使用默认构造函数
};
void doSomething()
{
    std::vector<Widget> v;
} //v在这里销毁
//假设v中包含多个Widget对象，销毁第一个时发生异常，销毁第二个时也发生异常，将产生未定义行为


//使用一个用于数据库连接的类
class DBConnection
{
public:
    static DBConnection creat(){};//返回DBConnection对象的函数；
    //如果创建失败，则抛出异常      //为简单起见，省略了参数
    void close(){}; //关闭数据库连接;如果关闭失败，则抛出异常
};
class DBConnectionManager //用来管理DBConnection对象的类
{
public:
    DBConnectionManager(DBConnection db) : db(db) //构造函数
    {
    }
    //如果调用产生了异常，DBConnectionManager的析构函数将传播该异常，即允许它离开析构函数。这回导致麻烦，因为析构函数吐出的异常很难处理。
    //有两种方法可以避免这种麻烦。DBConnectionManager的析构函数可以：
    ~DBConnectionManager() //确保数据库连接总是关闭的
    {
        //1.如果发生close抛出异常，就终止程序，通常可以调用abort
        try
        {
            db.close(); 
        }
        catch (...)
        {
            std::cerr << "DBConnectionManager destructor: close() failed" << std::endl;
            std::abort(); //终止程序
        }
        //2.如果发生close抛出异常，可以在日志中记录close调用失败的信息
        try
        {
            db.close(); 
        }
        catch (...)
        {
            //在日志中记录close调用失败的信息
        }
        //这两种方法都不是特别有吸引力。这两种方法的问题在于，程序无法对导致close抛出的异常的条件作出反应。
    }
private:
    DBConnection db;
};
//更好的策略是设计DBConnectionManager的接口，以便其使用者有机会对可能出现的问题作出反应。

class DBConnectionManager2 //用来管理DBConnection对象的类
{
public:
    void close() //关闭数据库连接;如果关闭失败，则抛出异常
    {
        db.close(); //关闭数据库连接
        closed = true; //标记数据库连接已关闭
    }
    ~DBConnectionManager2() //构造函数
    {
        if(!closed) //如果数据库连接没有关闭
        {
            try
            {
                db.close(); //关闭数据库连接
            }
            catch (...)
            {
                 //在日志中记录close调用失败的信息
            }
        }
    }
private:
    DBConnection db;
    bool closed; //标记数据库连接是否关闭
};
void item8()
{
    //开启一个块
    {
        DBConnectionManager dbcm(DBConnection::creat()); //创建DBConnectionManager对象
        //然后把它交给DbConnectionManager对象来管理
        //通过DbConnectionManager接口使用DbConnection对象
    }//块结束时，DbConnectionManager对象被销毁,自动在DbconnectionManager析构函数中调用db.close()

}
//析构函数永远不应该吐出（emit）异常。如果在析构函数中调用的函数可能抛出异常，则析构函数应该捕获任何异常，然后将其吞下或终止程序
//如果类客户需要能够对操作期间抛出的异常作出反应，则类应该提供执行该操作的普通函数。